package org.example.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.example.common.BaseParam;
import org.example.common.BusinessCode;
import org.example.common.HygResponse;
import org.example.common.MyRequestWrapper;
import org.example.utils.*;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @author liyishan
 * @date 2023/4/18 13:44
 */
@Slf4j
//@WebFilter(urlPatterns = "/*")
@WebFilter(urlPatterns = "/openApi/*")
public class MyFilter implements Filter  {

    public void init(FilterConfig filterConfig) {
        log.info("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long start = System.currentTimeMillis();
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        MyRequestWrapper  myRequestWrapper = new MyRequestWrapper(request);
        String body = myRequestWrapper.getBody();
        String requestURI = request.getRequestURI();
        String realIp = IpUtil.getRealIp(request);
        //健康检测
        if ("/".equals(requestURI)) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.SUCCESS));
            return;
        }
        if (StringUtils.isEmpty(body)) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_PARAMS));
            log.error("请求参数为空 ip:{}, URI:{}", realIp, requestURI);
            return;
        }
        BaseParam baseVo = JSON.parseObject(body, BaseParam.class);
        //2.获取商户id,然后获取用户缓存信息
        String cooperatorId = baseVo.getCooperatorId();
        log.info("请求开始(api), 商户id是:{}, ip:{}, uri:{}.", cooperatorId, realIp, requestURI);
        if (StringUtils.isEmpty(cooperatorId)) {
            log.error("没有传递外层商户ID...URI:{}", requestURI);
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_PARAMS));
            return;
        }
        if (StringUtils.isEmpty(baseVo.getBusinessBody())) {
            log.error("业务参数为空...cooperatorId:{},URI:{}", cooperatorId, requestURI);
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_PARAMS));
            return;
        }
        //从缓存中获取商户配置信息  OpenApiCoopertor，这里配置了针对某个商户的白名单列表，公钥，私钥等
        //验证ip白名单
        /**
         * if (CollectionUtils.isEmpty(openApiCooperator.getIpWhite()) || !openApiCooperator.getIpWhite().contains(realIp)) {
         *             //缓存判断
         *             if (BooleanUtils.isTrue(stringRedisTemplate.hasKey("TEMP_ALLOW_WHITE_LIST"))) {
         *                 log.info("跳过白名单配置");
         *             } else {
         *                 log.info("抛出白名单异常");
         *                 WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_IP_WHITE_LIST.getCode(), BusinessCode.ERROR_IP_WHITE_LIST.getDesc().concat(realIp)));
         *                 return;
         *             }
         *         }
         */
        //私钥解密
        //4.获取用户公钥和secretKey
        String publicKey ="1212";//= openApiCooperator.getPublicKey();
        String secretKey ="1212";//= openApiCooperator.getSecretKey();
        //5.验证签名
        String businessBody;
        try {
            businessBody = AESUtils.decryptByHex(baseVo.getBusinessBody(), secretKey);
        } catch (Exception e) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_PARAMS));
            log.error("解密请求参数失败-{}-{}-请求报文:\n{}", cooperatorId, requestURI, JSON.toJSONString(baseVo, SerializerFeature.PrettyFormat));
            log.error("解密请求参数失败 cooperatorId:{},URI:{},e:{}", cooperatorId, requestURI, e);
            /*mailUtil.asyncSendMailPerMinutes(HygConfig.Redis.SEND_EMAIL_FLAG.concat(cooperatorId), 10, mailUtil.developMails(),
                    "open-api调用错误", "原因是:解密请求参数失败,商户id是:".concat(cooperatorId).concat("\n请求报文:").concat(baseVo.getBusinessBody()));
            */
            return;
        }
        Map<String, Object> baseVo1 = JSON.parseObject(businessBody,Map.class);
        String sign = String.valueOf(baseVo1.get("sign"));
        baseVo1.remove("sign");
        String sortStr = RSAUtils.sortParam(baseVo1);
        try {
            if (!RSAUtils.verify(sortStr.getBytes(), publicKey, sign)) {
                log.error("验签失败,参数可能被篡改 cooperatorId:{},URI:{}", cooperatorId, requestURI);
                WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_SIGN));
                /*mailUtil.asyncSendMailPerMinutes(HygConfig.Redis.SEND_EMAIL_FLAG.concat(cooperatorId), 10, mailUtil.developMails(),
                        "open-api调用错误", "原因是:验签失败,参数不对或公私钥不对,商户id是:".concat(cooperatorId).concat("参数密文:").concat(body));*//*
                */
                return;
            }
        } catch (Exception e) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_SIGN));
            log.error("验签出现异常 cooperatorId:{},URI:{},e:{}", cooperatorId, requestURI, e);
            /*mailUtil.asyncSendMailPerMinutes(HygConfig.Redis.SEND_EMAIL_FLAG.concat(cooperatorId), 10, mailUtil.developMails(),
                    "open-api调用错误", "原因是:验签出现异常,商户id是:".concat(cooperatorId).concat("参数密文:").concat(body));
            */
            return;
        }
        Object timestamp = baseVo1.get("timestamp");
        if (null == timestamp || StringUtils.isEmpty(String.valueOf(timestamp))) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_PARAMS));
            log.error("请求时间戳校验为空, cooperatorId:{},URI:{}", cooperatorId, requestURI);
            /*mailUtil.asyncSendMailPerMinutes(HygConfig.Redis.SEND_EMAIL_FLAG.concat(cooperatorId), 10, mailUtil.developMails(),
                    "open-api调用错误", "原因是:请求时间戳校验为空,商户id是:".concat(cooperatorId));
            */
            return;
        }
        long l = FuDateUtil.diffMin(start, Long.parseLong(timestamp.toString()));
        if (l >= 10L) {
            WriterUtil.writerJson(response, new HygResponse<>(BusinessCode.ERROR_TIMESTAMP));
            log.error("请求时间戳校验发现相差10分中以上,请求异常 cooperatorId:{},URI:{},l:{}", cooperatorId, requestURI, l);
            /*//*mailUtil.asyncSendMailPerMinutes(HygConfig.Redis.SEND_EMAIL_FLAG.concat(cooperatorId), 10, mailUtil.developMails(),
                    "open-api调用错误", "原因是:请求时间戳校验发现相差10分中以上,商户id是:".concat(cooperatorId));
            */
            return;
        }
        //修改流之后可以让controller层读取
        myRequestWrapper.setBody(businessBody);
        //异步保存请求记录
        String requestIp = IpUtil.getRequestIp(request);
        filterChain.doFilter(myRequestWrapper, response);
        log.info("Api request uri:{},use time :{}ms.\n", requestURI, System.currentTimeMillis() - start);

    }



    @Override
    public void destroy() {
        log.info("过滤器已销毁");
    }
}
